//
// Created by martin on 1/28/22.
//

#ifndef MYMUDUO_STRINGPIECE_H
#define MYMUDUO_STRINGPIECE_H

#include "Types.h"

namespace muduo
{

/*
 * For passing C-style string argument to a function.
 */
class StringArg
{
public:
    StringArg(const char* str)
    : str_(str)
    { }

    StringArg(const string& str)
    : str_(str.c_str())
    { }

    const char* c_str() const { return str_; }

private:
    const char* str_;
};

class StringPiece
{
public:
    StringPiece()
    : ptr_(NULL), length_(0) { }
    StringPiece(const char* str)
    : ptr_(str), length_(static_cast<int>(strlen(ptr_))) { }
    StringPiece(const unsigned char* str)
    : ptr_(reinterpret_cast<const char*>(str)),
    length_(static_cast<int>(strlen(ptr_))) { }
    StringPiece(const string& str)
    : ptr_(str.data()), length_(static_cast<int>(str.size())) { }
    StringPiece(const char* offset, int len)
    : ptr_(offset), length_(len) { }

    /**
     * data() may return a pointer to a buffer with embedded NULs, and the
     * returned buffer may or may not be null terminated. Therefore it is
     * typically a mistake to pass data() to a routine that expects a NUL
     * terminated string. Use "as_string().c_str()" if you really need to do
     * this. Or better yet, change your routine so it does not rely on NUL
     * termination.
     */
    const char* data() const { return ptr_; }
    int size() const { return length_; }
    bool empty() const { return length_ == 0; }
    const char* begin() const { return ptr_; }
    const char* end() const { return ptr_ + length_; }

    void clear() { ptr_ = NULL; length_ = 0; }
    void set(const char* buffer, int len) { ptr_ = buffer; length_ = len; }
    void set(const char* str) {
        ptr_ = str;
        length_ = static_cast<int>(strlen(str));
    }

    char operator[](int i) const { return ptr_[i]; }

    void remove_prefix(int n)
    {
        ptr_ += n;
        length_ -= n;
    }

    void remove_suffix(int n)
    {
        length_ -= n;
    }

    bool operator==(const StringPiece& x) const
    {
        return ((length_ == x.length_) &&
                (memcmp(ptr_, x.ptr_, static_cast<size_t>(length_)) == 0));
    }

    bool operator!=(const StringPiece& x) const
    {
        return !(*this == x);
    }

#define STRINGPIECE_BINARY_PREDICATE(cmp,auxcmp) \
    bool operator cmp (const StringPiece& x) const \
    { \
        size_t len = static_cast<size_t>(length_ < x.length_ ? length_ : x.length_); \
        int r = memcmp(ptr_, x.ptr_, len); \
        return ((r auxcmp 0) || ((r == 0) && (length_ cmp x.length_)));                                                 \
    }
    STRINGPIECE_BINARY_PREDICATE(<, <);
    STRINGPIECE_BINARY_PREDICATE(<=, <);
    STRINGPIECE_BINARY_PREDICATE(>=, >);
    STRINGPIECE_BINARY_PREDICATE(>, >);
#undef STRINGPIECE_BINARY_PREDICATE

    int compare(const StringPiece& x) const
    {
        size_t len = static_cast<size_t>(length_ < x.length_ ? length_ : x.length_);
        int r = memcmp(ptr_, x.ptr_, len);
        if (r == 0)
        {
            if (length_ < x.length_) r = -1;
            else if (length_ > x.length_) r = 1;
        }
        return r;
    }

    string as_string() const
    {
        return string(data(), static_cast<unsigned long>(size()));
    }

    void CopyToString(string* target) const
    {
        target->assign(ptr_, static_cast<unsigned long>(length_));
    }

    bool starts_with(const StringPiece& x) const
    {
        size_t len = static_cast<size_t>(x.length_);
        return ((length_ >= x.length_) && (memcmp(ptr_, x.ptr_, len)));
    }

private:
    const char* ptr_;
    int length_;
};

} // namespace muduo

/* ------------------------------------------------------------------
 * Functions used to create STL containers that use StringPiece
 * Remember that a StringPiece's lifetime had better be less than
 * of the underlying string or char*. If it is not, then you
 * cannot safely store a StringPiece into an STL container
 * ------------------------------------------------------------------
 */

#ifdef HAVE_TYPE_TRAITS
// This makes vector<StringPiece> really fast for some STL implements
template<> struct __type_traits<muduo::StringPiece> {
    typedef __true_type has_trivial_default_constructor;
    typedef __true_type has_trivial_copy_constructor;
    typedef __true_type has_trivial_assignment_constructor;
    typedef __true_type has_trivial_destructor;
    typedef __true_type is_POD_type;
};
#endif

// allow StringPiece to be logged
std::ostream& operator<<(std::ostream& os, const muduo::StringPiece& piece);

#endif //MYMUDUO_STRINGPIECE_H
